home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
programr
/
dpmigcc5.zip
/
RSX
/
SOURCE
/
KDEB.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-05-27
|
10KB
|
435 lines
/*****************************************************************************
* FILE: kdeb.c *
* *
* DESC: *
* - support for kernel debugging *
* - kernel ptrace *
* *
* Copyright (C) 1993,1994 *
* Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld *
* email: rainer@mathematik.uni-bielefeld.de *
* *
*****************************************************************************/
#include "DPMI.H"
#include "KDEB.H"
#include "PROCESS.H"
#include "PTRACE.H"
#include "DOSERRNO.H"
#include "START32.H"
#include "ADOSX32.H"
#include "SIGNALS.H"
#include "PRINTF.H"
#define SINGLE_STEP 0x100
#define RESUME_FLAG 0x10000L
#define FLAG_MASK 0x00000dd9L
#define BREAKPOINT 0xcc
#define MAX_HARD 4
#define BP_FLAG_MASK 0x0FFF
#define BP_ENABLE 0x1000
#define BP_DISABLE 0x2000
typedef struct {
DWORD address;
WORD handle;
WORD flags;
DWORD data;
DWORD pt_address;
} HardBreakPoint;
static HardBreakPoint hbp[MAX_HARD];
static DWORD memaddress;
static int KDEB_set_hard_break(DWORD at_address, WORD flags)
{
int i;
if (!memaddress)
GetBaseAddress(GetCS(), & memaddress);
for (i = 1; i < MAX_HARD; i++)
if (hbp[i].flags == 0)
break;
if (i >= MAX_HARD)
return -1;
if (SetDebugWatchpoint(memaddress + at_address,
flags & BP_FLAG_MASK, &hbp[i].handle)) {
puts("set_hard_break() error");
return -1;
}
else {
hbp[i].address = at_address;
hbp[i].flags = flags | BP_ENABLE;
return i;
}
}
static int KDEB_del_hard_break(int no)
{
if (no >= MAX_HARD || hbp[no].flags == 0)
return -1;
if (hbp[no].flags & BP_DISABLE) {
/* already clear */
hbp[no].address = 0;
hbp[no].flags = 0;
hbp[no].handle = 0;
return 0;
}
if (ClearDebugWatchpoint(hbp[no].handle)) {
puts("del_hard_break() error");
return -1;
}
else {
hbp[no].address = 0;
hbp[no].flags = 0;
hbp[no].handle = 0;
return 0;
}
}
static int KDEB_disable_hard_break(int no)
{
if (no <= 1 && no >= MAX_HARD)
return -1;
if (hbp[no].flags & BP_DISABLE)
return -1;
if (ClearDebugWatchpoint(hbp[no].handle)) {
puts("disable_hard_break() error");
return -1;
}
else {
hbp[no].flags &= BP_FLAG_MASK;
hbp[no].flags |= BP_DISABLE;
return 0;
}
}
static int KDEB_enable_hard_break(int no)
{
if (no <= 1 && no >= MAX_HARD)
return -1;
if (hbp[no].flags & BP_ENABLE)
return -1;
if (SetDebugWatchpoint(memaddress + hbp[no].address,
hbp[no].flags & BP_FLAG_MASK, &hbp[no].handle)) {
puts("enable_hard_break() error");
return -1;
}
else {
hbp[no].flags &= BP_FLAG_MASK;
hbp[no].flags |= BP_ENABLE;
return 0;
}
}
int KDEB_check_breakpoints(DWORD pc)
{
int i;
WORD j;
for (i = 0; i < MAX_HARD; i++)
if (hbp[i].flags & BP_ENABLE) {
j = 0;
GetStateDebugWatchpoint(hbp[i].handle, &j);
if (j)
ResetDebugWatchpoint(hbp[i].handle);
}
return ((i >= MAX_HARD) ? -1 : i);
}
void KDEB_enable_breakpoints(void)
{
int i;
for (i = 0; i < MAX_HARD; i++)
if ((hbp[i].flags & BP_DISABLE) && hbp[i].pt_address)
KDEB_enable_hard_break(i);
}
void KDEB_disable_breakpoints(void)
{
int i;
for (i = 0; i < MAX_HARD; i++)
if ((hbp[i].flags & BP_ENABLE) && hbp[i].pt_address)
KDEB_disable_hard_break(i);
}
/* +++++++++++++ PTRACE in KERNEL +++++++++++++++++ */
/* crt0.s */
extern unsigned long rsx_data_start;
extern unsigned long rsx_data_ends;
/*
* simulate ptrace(pid,POKETEXT,address,BREAKPOINT/ORGINAL)
*/
static int KDEB_ptrace_poketext(DWORD address, DWORD value)
{
int i;
DWORD bp = value;
DWORD bp_addr = address;
for (i = 0 ; i <= 3 ; i++) {
if ((bp & 0xff) == BREAKPOINT)
break;
bp >>= 8;
bp_addr ++;
}
/* ptrace: set breakpoint in text */
if (i <= 3) {
printf("POKETEXT new break %lX\n", address);
if ((i = KDEB_set_hard_break(bp_addr, BREAK_CODE)) > 0) {
KDEB_disable_hard_break(i);
hbp[i].data = value;
hbp[i].pt_address = address;
return 0;
}
else {
printf("POKETEXT break fail %lX\n", address);
return -1;
}
}
/* ptrace: delete breakpoint in text */
else {
for (i = 0; i < MAX_HARD; i++)
if (address == hbp[i].pt_address)
break;
if (i >= MAX_HARD) {
printf("POKETEXT address %lX\n", address);
* (DWORD *) address = value;
}
else {
printf("POKETEXT delete break %lX\n", address);
hbp[i].data = hbp[i].pt_address = 0;
KDEB_del_hard_break(i);
}
return 0;
}
}
/*
* simulate ptrace(pid,PEEKTEXT,address, 0)
*/
static int KDEB_ptrace_peektext(DWORD address, DWORD * value)
{
int i;
for (i = 0; i < MAX_HARD; i++)
if (address == hbp[i].pt_address)
break;
if (i >= MAX_HARD) {
/* printf("PEEKTEXT address %lX\n", address); */
*value = * (DWORD *) address;
}
else {
/* printf("PEEKTEXT peek break %lX\n", address); */
*value = hbp[i].data;
}
return 0;
}
/*
* simulate ptrace(pid,POKEDATA,address,value)
*/
static int KDEB_ptrace_pokedata(DWORD address, DWORD value)
{
if (address < 4096 || address >= rsx_data_ends) {
puts("KDEB: illegal address");
return EMX_EINVAL;
}
if (address == (DWORD) & npz) {
puts("KDEB: don't touch npz");
return EMX_EINVAL;
}
* (DWORD *) address = value;
return 0;
}
/*
* simulate ptrace(pid,PEEKDATA,address,0)
*/
static int KDEB_ptrace_peekdata(DWORD address, DWORD * value)
{
if (address < 4096 || address >= rsx_data_ends) {
puts("KDEB: illegal address");
return EMX_EINVAL;
}
if (address == (DWORD) & npz) {
*value = (DWORD) RSX_PROCESS.cptr;
return 0;
}
*value = * (DWORD *) address;
return 0;
}
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
int KDEB_ptrace(int request, DWORD addr, DWORD data, DWORD * ret)
{
/* printf("KDEB %d %lX %lX\n", request, addr, data); */
*ret = 0;
switch (request) {
case PTRACE_TRACEME:
case PTRACE_SESSION:
return 0;
case PTRACE_PEEKTEXT:
case PTRACE_PEEKDATA:
if (addr > 0x10000L && addr < rsx_data_start)
return KDEB_ptrace_peektext(addr, ret);
else
return KDEB_ptrace_peekdata(addr, ret);
case PTRACE_POKETEXT:
if (addr > 0x10000L && addr < rsx_data_start)
return KDEB_ptrace_poketext(addr, data);
else
return KDEB_ptrace_pokedata(addr, data);
case PTRACE_EXIT:
KDEB_disable_breakpoints();
return 0;
case PTRACE_PEEKUSER:
if (addr == 0x30) { /* u_ar0 */
*ret = 0xE0000000 + ((DWORD) (UINT) & (RSX_PROCESS.regs));
return 0;
} else { /* peek regs */
DWORD *peekat;
peekat = (DWORD *) (UINT) (addr);
if (peekat < &(RSX_PROCESS.regs.gs) || peekat > &(RSX_PROCESS.regs.ss))
return EMX_EIO;
*ret = *peekat;
if (peekat == &(RSX_PROCESS.regs.eip)) {
int i;
for (i = 0; i < MAX_HARD; i++)
if (RSX_PROCESS.regs.eip == hbp[i].address)
break;
if (i < MAX_HARD)
(*ret)++;
}
return 0;
}
case PTRACE_POKEUSER:
/* don't change kernel registers ! */
*ret = data;
return 0;
case PTRACE_STEP:
/* printf("PTRACE step\n"); */
RSX_PROCESS.regs.eflags |= SINGLE_STEP;
npz = RSX_PROCESS.cptr;
KDEB_rsx32_orgjmp();
return 0;
case PTRACE_RESUME:
/* printf("PTRACE resume\n"); */
RSX_PROCESS.regs.eflags &= ~SINGLE_STEP;
npz = RSX_PROCESS.cptr;
KDEB_enable_breakpoints();
/* start first program */
if (npz == & process[2] && npz->regs.eip == 0x10000)
back_from_syscall();
KDEB_rsx32_orgjmp();
return 0;
default:
return EMX_EIO;
}
}
struct POPAD {
unsigned edi;
unsigned esi;
unsigned ebp;
unsigned esp;
unsigned ebx;
unsigned edx;
unsigned ecx;
unsigned eax;
};
#define RSXREG RSX_PROCESS.regs
static unsigned rsx_eip;
static unsigned rsx_flags;
static unsigned rsx_esp;
void KDEB_debug_handler(void)
{
KDEB_check_breakpoints(RSXREG.eip);
KDEB_disable_breakpoints();
/*
printf("Debug fault at %04X:%08lX efl=%08lX\n",
RSXREG.cs & 0xFFFF, RSXREG.eip, RSXREG.eflags);
*/
rsx_eip = RSXREG.eip;
RSX_PROCESS.p_status = PS_STOP;
RSX_PROCESS.wait_return = (SIGTRAP << 8) | 127;
RSX_PROCESS.p_flags |= PF_WAIT_WAIT;
RSX_PROCESS.cptr = npz;
npz = & process[1];
EAX = ECX = 0;
npz->p_status = PS_RUN;
/* ptrace should go on other stack */
stackp16 -= 8000;
back_from_syscall();
}
volatile void KDEB_rsx32_orgjmp(void)
{
struct POPAD pop;
/* ptrace should go on other stack */
stackp16 += 8000;
pop.eax = RSXREG.eax;
pop.ecx = RSXREG.ecx;
pop.edx = RSXREG.edx;
pop.ebx = RSXREG.ebx;
pop.esp = RSXREG.esp;
pop.ebp = RSXREG.ebp;
pop.esi = RSXREG.esi;
pop.edi = RSXREG.edi;
rsx_eip = RSXREG.eip;
rsx_flags = RSXREG.eflags;
rsx_esp = RSXREG.esporg;
loop:
__asm__ __volatile (
"movl %0, %%esp \n\t"
"popa \n\t"
"nop \n\t"
"movl _rsx_esp, %%esp \n\t"
"pushl _rsx_flags\n\t"
"pushl %%cs \n\t"
"pushl _rsx_eip \n\t"
"iret \n\t"
:
: "r" ((unsigned)&pop)
);
goto loop;
}